您可以配置preStop Hook,实现ALB Ingress后端Pod的平滑下线,使Pod在被ALB Ingress Controller完全从后端服务组中移除后才正式下线。配置后,容器在滚动更新期间能够保障服务的流量无缝切换,避免出现中断。
前提条件
已创建ACK托管集群或ACK专有集群,且集群为v1.18及以上版本。具体操作,请参见创建ACK托管集群、创建ACK专有集群;如需升级集群,请参见手动升级集群。
已为集群安装ALB Ingress Controller组件。具体操作,请参见管理ALB Ingress Controller组件。
说明若需要在ACK专有集群中通过ALB Ingress访问服务,在部署服务前需要为ALB Ingress Controller授权。具体操作,请参见为ACK专有集群授予ALB Ingress Controller访问权限。
已通过kubectl工具连接集群。具体操作,请参见获取集群KubeConfig并通过kubectl工具连接集群。
已创建ALBConfig和IngressClass。具体操作,请参见创建ALBConfig。
原理介绍
Pod生命周期
Pod中的容器包括两种类型:
初始化容器(Init容器):运行服务的主容器前置依赖的容器,完成一些初始化操作。
主容器(工作容器):运行服务进程的容器。
Pod启动过程如下:
运行初始化容器:在主容器启动之前,要运行的容器,为主容器执行预置操作。
运行主容器:
容器启动后执行postStart Hook函数。
容器执行存活性探测(Liveness Probe)、就绪性检测(Readiness Probe)。
在容器退出前执行preStop Hook函数。
Pod终止流程和网络规则更新流程
在删除Pod时K8s会同时进行Pod终止和网络规则更新两个主要的流程。Pod终止流程和网络更新流程如下。
Pod终止流程
kube-apiserver收到Pod删除请求,将Pod标记为
Terminating
状态。如果Pod定义了preStop Hook,将执行preStop Hook。
K8s集群向容器发送SIGTERM信号。
等待容器停止,或等待Pod删除宽限期超时。
说明Pod中容器删除宽限期
terminationGracePeriodSeconds
默认为30秒。超时Pod删除宽限期后容器仍未终止,K8s发送SIGKILL信号给容器。
Pod被完全删除。
网络规则更新流程
kube-apiserver收到Pod删除请求,将Pod标记为
Terminating
状态。Endpoint Controller从Endpoint对象中删除Pod的IP。
ALB Ingress Controller进行Server节点调谐,将Service Endpoints从后端服务器组中移除,不再将流量路由到被删除的Pod。
使用preStop Hook来实现Pod平滑下线
当Pod滚动升级过程中,如果旧的Pod没有平滑退出,将导致应用无法正常处理业务请求,出现如下错误状态码,影响应用的可用性。
状态码 | 问题原因 |
504 | 当旧Pod在未处理完正常请求情况下被删除,并且该请求为非幂等。 |
502 | 当ACK集群已经删除旧Pod,容器收到终止信号(SIGTERM)并迅速终止,但ALB Ingress Controller仍在调谐流程中,导致Pod未及时从后端服务器组中移除,流量依然被错误地路由到已终止的旧Pod上。 |
为了避免以上的情况发生,您可以采取如下方案。
在kube-apiserver接收到Pod删除请求时,通过在Deployment配置内添加preStop Hook,可以为容器设置一个"Sleep"暂停期。这个暂停期是让容器有时间在收到SIGTERM之前完成网络规则的更新,并等待ALB Ingress Controller完成Server调谐事件并确保Pod已从后端服务器组中移除。这一步骤对于保障Pod的平稳下线至关重要,避免在滚动更新或服务重启期间造成流量中断。
同时,Kubernetes为容器设定了在接收到SIGTERM后能持续运行的最大宽限期(terminationGracePeriodSeconds)为30秒。当程序关闭时间与preStop Hook指定的操作时间之和超过了30秒时,默认宽限期将不足以让容器完成所有的关闭步骤。kubelet会在等待2秒后直接给容器发送立即终止(SIGKILL)信号,导致容器强制退出。
如果程序的关闭时间和在Deployment配置的preStop Hook之和超过30秒,应将terminationGracePeriodSeconds
重新设置,调整为大于30秒,确保容器优雅退出。
步骤一:并配置Pod平滑退出preStop Hook
创建并保存tea-service.yaml,配置确保Pod平滑退出的preStop Hook。
apiVersion: apps/v1 kind: Deployment metadata: name: tea spec: replicas: 3 selector: matchLabels: app: tea template: metadata: labels: app: tea spec: containers: - name: tea image: registry.cn-hangzhou.aliyuncs.com/acs-sample/nginxdemos:latest ports: - containerPort: 80 lifecycle: # 设置preStop Hook函数,使kube-apiserver等待10秒后再向Pod发送SIGTERM信号。 preStop: # preStop钩子设置。 exec: # 通过执行命令的方式来实现preStop操作。 command: # 定义要执行的命令。 - /bin/sh - -c - "sleep 10" # 执行sleep操作,暂停10秒。 terminationGracePeriodSeconds: 45 # 设置Pod删除宽限期。 --- apiVersion: v1 kind: Service metadata: name: tea-svc spec: ports: - port: 80 targetPort: 80 protocol: TCP selector: app: tea type: NodePort
执行以下命令,部署示例Deployment和Service。
kubectl apply -f tea-service.yaml
创建并保存tea-ingress.yaml文件,用于配置Ingress。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: tea-ingress spec: ingressClassName: alb rules: - host: demo.ingress.top http: paths: - path: / pathType: Prefix backend: service: name: tea-svc port: number: 80
执行以下命令,部署Ingress。
kubectl apply -f tea-ingress.yaml
执行以下命令,获取ALB Ingress的
ADDRESS
。kubectl get ingress
预期输出:
NAME CLASS HOSTS ADDRESS PORTS AGE tea-ingress alb demo.ingress.top alb-110zvs5nhsvfv*****.cn-chengdu.alb.aliyuncs.com 80 7m5s
步骤二:结果验证
启动测试脚本。
使用以下内容,创建
test.sh
测试脚本文件。此脚本用于测试应用的可用性,按每秒一次的频率请求Nginx服务并查看状态码。#!/bin/bash HOST="demo.ingress.top" DNS="alb-110zvs5nhsvfv*****.cn-chengdu.alb.aliyuncs.com" # 填写ALB Ingress的ADDRESS值。 printf "Response Code|| TIME \n" >> log.txt while true; do RESPONSE=$(curl -H Host:$HOST -s -o /dev/null -w "%{http_code}" -m 1 http://$DNS/) TIMESTAMP=$(date +%Y-%m-%d_%H:%M:%S) echo "$TIMESTAMP - $RESPONSE" >> log.txt sleep 1 done
执行以下命令运行测试脚本
test.sh
。bash test.sh
执行以下命令,重新部署应用,触发Pod滚动升级。
kubectl rollout restart deploy tea
验证Pod滚动升级。
初始阶段应用副本数为3。
在重新部署应用时,新Pod创建阶段由于新Pod没有就绪,旧Pod仍在提供服务,会同时运行新旧两个Pod。
新Pod就绪且成功挂载至ALB后端服务器组后,会终止旧Pod。
所有旧Pod完成preStop Hook函数或超出
terminationGracePeriodSeconds
超时时间后,kubectl
会向Container发送信号终止旧的Pod,此时滚动更新完成。
查看测试脚本执行结果。检查滚动更新过程中请求的状态码,可以看到状态码全部为200,更新过程没有中断。
执行如下命令,查看测试脚本执行结果。
cat log.txt
预期输出:
相关文档
您可以使用ALB Ingress将来自不同域名或URL路径的请求转发给不同的后端服务器组、将HTTP访问重定向至HTTPS以及实现灰度发布等功能,请参见ALB Ingress服务高级用法
您可以通过配置ReadinessGate来保证Pod上线阶段的可用性,请参见使用ReadinessGate实现ALB Ingress后端Pod滚动升级时平滑上线。
如在使用ALB Ingress过程中遇到问题,您可以参见ALB Ingress FAQ、ALB Ingress异常问题排查进行自排查。